﻿namespace NTLib.Pipe.Network.Descriptors
{
    using Connectors;
    using NTLib.Core.Reflection;
    using NTLib.Core.Descriptors;
    using NTLib.Pipe.Descriptors;
    using System;
    using Core.Attributes;
    using Streaming.Formats;

    /// <summary>
    /// Define all the necessary information for a pipe throuth net to be created.
    /// </summary>
    /// <seealso cref="NTLib.Core.Descriptors.Descriptor" />
    /// <seealso cref="NTLib.Pipe.Descriptors.ITargetDescriptor" />
    public class NetworkTargetDescription : Descriptor, ITargetDescriptor
    {
        #region Fields

        private readonly NetworkConnectorDescription _connector;
        private readonly NetworkFormatDescription _formater;
        private readonly INetworkAddress _address;
        private readonly bool _isHost;

        #endregion

        #region Ctor
        /// <summary>
        /// Initializes a new instance of the <see cref="NetworkTargetDescription"/> class.
        /// </summary>
        /// <param name="connector">The connector.</param>
        /// <param name="formater">The formater.</param>
        /// <param name="id">The identifier.</param>
        public NetworkTargetDescription(NetworkConnectorDescription connector, NetworkFormatDescription formater, INetworkAddress address, bool isHost = false, Guid id = default(Guid))
            : base(id)
        {
            this._connector = connector;
            this._formater = formater;
            this._address = address;
            this._isHost = isHost;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the name.
        /// </summary>
        public override string Name
        {
            get { return base.Name; }
        }

        /// <summary>
        /// Gets the connector.
        /// </summary>
        public NetworkConnectorDescription Connector
        {
            get { return this._connector; }
        }

        /// <summary>
        /// Gets the formater.
        /// </summary>
        public NetworkFormatDescription Formater
        {
            get { return this._formater; }
        }

        /// <summary>
        /// Gets the network address.
        /// </summary>
        public INetworkAddress Address
        {
            get { return this._address; }
        }

        public bool IsHost
        {
            get { return this._isHost; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Equalses the specified other.
        /// </summary>
        /// <param name="other">The other.</param>
        /// <returns></returns>
        public bool Equals(ITargetDescriptor other)
        {
            bool equal = !object.Equals(other, null) && other.Id == this.Id && other.GetType() == this.GetType();

            if (equal)
            {
                NetworkTargetDescription nOther = (NetworkTargetDescription)other;
                equal = nOther.Formater == this.Formater && nOther.Connector == nOther.Connector;

                if (equal)
                    equal = Address == this.Address;
            }
            return equal;
        }

        /// <summary>
        /// Creates a new NetworkTargetDescrition using the type of the connector and the formator you want to use.
        /// </summary>
        /// <typeparam name="C"></typeparam>
        /// <typeparam name="F"></typeparam>
        /// <param name="address">The address.</param>
        /// <param name="isHost">if set to <c>true</c> [is host].</param>
        /// <param name="id">The identifier.</param>
        /// <param name="registerComponent">if set to <c>true</c> [register component].</param>
        /// <returns></returns>
        public static NetworkTargetDescription Create<C, F>(Uri address, bool isHost, Guid id = default(Guid), bool registerComponent = true)
            where C : IConnector
            where F : IPackageFormater
        {
            return Create<C, F>(new NetworkAddressDescription(address), isHost, id, registerComponent);
        }

        /// <summary>
        /// Creates a new NetworkTargetDescrition using the type of the connector and the formator you want to use.
        /// </summary>
        /// <typeparam name="C"></typeparam>
        /// <typeparam name="F"></typeparam>
        /// <param name="address">The address.</param>
        /// <param name="isHost">if set to <c>true</c> [is host].</param>
        /// <param name="id">The identifier.</param>
        /// <param name="registerComponent">if set to <c>true</c> [register component].</param>
        /// <returns></returns>
        public static NetworkTargetDescription Create<C, F>(INetworkAddress address, bool isHost, Guid id = default(Guid), bool registerComponent = true)
            where C : IConnector
            where F : IPackageFormater
        {
            var connectorID = typeof(C).GetMandatoryAttribute<GuidAttribute>(false);
            var formatorID = typeof(F).GetMandatoryAttribute<GuidAttribute>(false);

            if (registerComponent)
            {
                ConnectorManager.Instance.Register<C>();
                
                PackageFormatManager.Instance.Register<F>();
            }

            NetworkConnectorDescription net = new NetworkConnectorDescription(connectorID.Value, typeof(C).Name);
            NetworkFormatDescription format = new NetworkFormatDescription(formatorID.Value, typeof(F).Name);

            return new NetworkTargetDescription(net, format, address, isHost, id);
        }

        #endregion
    }
}
